<?php
/**
 *  @author zxg 
 */
defined("LAJP_IP") || define("LAJP_IP", "127.0.0.1");     //Python端IP
defined("LAJP_PORT") ||define("LAJP_PORT", 21230);         //Python端侦听端口
defined("PARAM_TYPE_ERROR") ||define("PARAM_TYPE_ERROR", 101);    //参数类型错误
defined("SOCKET_ERROR") ||define("SOCKET_ERROR", 102);        //SOCKET错误
defined("LAJP_EXCEPTION") ||define("LAJP_EXCEPTION", 104);      //Python端反馈异常

class ZPScoreImport{
    CONST BATCHNUM = 500;
    CONST UPLOAD_SCORE = 1;
    CONST UPLOAD_STUDENT = 2;
    CONST BATCH_CACHE = 3;
    private $titleLineNum = 0;
    private $filePath;
            
    /**
     * construct
     * @param type $fileName excel 存储全路径
     * @param type $titleLineNum excel 标题行位置
     */
    public function __construct($fileName,$titleLineNum=0) {
        $this->filePath = $fileName;
        $this->titleLineNum = $titleLineNum;
    }
    /**
     * excel存储位置
     * @return type 
     */
    public static function getExcelSavePath($buss=self::UPLOAD_SCORE){
        switch ($buss){
            case self::UPLOAD_SCORE:
                return UPLOAD_PATH . '/scores';
                break;
            case self::UPLOAD_STUDENT:
                return UPLOAD_PATH . '/info';
                break;
            case self::BATCH_CACHE:
                return UPLOAD_PATH . '/batch_cache';
                break;
            default:
                return false;
                break;
        }
    }
    public  function statisScore($examID){
        return $this->ppython("statis::total",$examID);
    }
    /**
     * 批量获取
     * @param type $batch
     * @param type $num
     * @return type 
     */
    public  function fetchBatchData($batch ,$num){
        return $this->ppython("excel::getBatch",0,$this->filePath,$this->titleLineNum,$batch,$num);
    }
    /**
     * 获取全部数据
     * @return type 
     */
    public function fetchAll(){
        return $this->ppython("excel::getAll",0,$this->filePath,$this->titleLineNum);
    }
    /**
     * 读取并序列化存储excel
     * def pickExcel(sheetIndex, xlsFilePath, savePath, titleRowNum): 
     */
    public  function pickExcel($xlsFilePath, $savePath){
         return $this->ppython("excel::pickExcel",0,$xlsFilePath,$savePath,$this->titleLineNum);
    }
    /**
     * fetchPickBatch(batchIndex, pickPath, bcount) 
     */
    public  function fetchPickBatch($batchIndex,$pickPath,$bcount){
        return $this->ppython("excel::fetchPickBatch",$batchIndex,$pickPath,$bcount);
    }
    /**
     * 目前只支持2003
     * @param type $fileName
     * @return boolean 
     */
    public static function isSupportExcelVersion($fileName){
        $extend = self::getFileExtName($fileName);
        if($extend!='xls'){
            return false;
        }
        return true;
    }
    /**
     * 生成请求salt
     * @param type $str
     * @return type 
     */
    public static function salt($str){
        return md5($str."MCHDN/FT*EHGJA_+@");
    }
    /**
     * excel 为分批导入为保证其中某个字段唯一将这个字段数组缓存到文件，每批数据读取缓存判断唯一
     * @param type $cacheFileName
     * @return boolean 
     */
    public static function fetchUniqueCache($cacheFileName){
        $cachePath = self::getExcelSavePath(self::BATCH_CACHE).'/'.$cacheFileName.".cache";
        if(file_exists($cachePath))
            return  @include($cachePath);
        return false;
    }
     /**
     * excel 为分批导入为保证其中某个字段唯一将这个字段数组缓存到文件，每批数据读取缓存判断唯一
     * @param type $cacheFileName
     * @return boolean 
     */
    public static function saveUniqueCache($arr,$cacheFileName){
        if(!is_array($arr) || empty($arr))
            return true;
        $cacheContent = '<?php return '. var_export($arr,true).';?>';
        $cachePath = self::getExcelSavePath(self::BATCH_CACHE);
        if(!$cacheFileName || !self::createDirs($cachePath)){
            return false;
        }
        $cachePath .= '/'.$cacheFileName.".cache";
        @file_put_contents($cachePath,$cacheContent);
    }
     /**
     * excel 为分批导入为保证其中某个字段唯一将这个字段数组缓存到文件，每批数据读取缓存判断唯一
     * @param type $cacheFileName
     * @return boolean 
     */
    public static function clearUniqueCache($cacheFileName){
        $cachePath = self::getExcelSavePath(self::BATCH_CACHE).'/'.$cacheFileName.".cache";
        file_exists($cachePath) && @unlink($cachePath);
    }
    /**
     * 保存批处理sql
     * @param type $batch
     * @param type $filename
     * @param type $sql
     * @return boolean 
     */
    public static function saveBatchSql($batch, $filename, $sql){
        if(!is_numeric($batch) || empty($sql) || empty($filename))
            return false;
        $cachePath = self::getExcelSavePath(self::BATCH_CACHE);
        if(!self::createDirs($cachePath)){
            return false;
        }
        $cachePath .= "/{$filename}_{$batch}_.batch";
        file_put_contents($cachePath, $sql);
    }
    /**
     * 获取批处理sql
     * @param type $batch
     * @param type $filename
     * @return boolean 
     */
    public static function fetchBatchSql($batch, $filename){
        $cachePath = self::getExcelSavePath(self::BATCH_CACHE)."/{$filename}_{$batch}_.batch";
        if(file_exists($cachePath))
            return file_get_contents ($cachePath);
        return false;
    }
    /**
     * 删除批量sql
     * @param type $batch
     * @param type $filename 
     */
    public static function clearBatchSql($batch, $filename){
        $cachePath = self::getExcelSavePath(self::BATCH_CACHE)."/{$filename}_{$batch}_.batch";
        file_exists($cachePath) && @unlink($cachePath);
    }
    /**
     * 删除批量sql文件
     * @param type $filename 
     */
    public static function clearBatchSqlAll($filename){
        for($batch=1;$batch<255;$batch++){
            $cachePath = self::getExcelSavePath(self::BATCH_CACHE)."/{$filename}_{$batch}_.batch";
            if(file_exists($cachePath))
                @unlink($cachePath);
            else
                break;
        }
    }
    /**
     * 区外成绩excel模板列
     * @return type 
     */
    public static function getOutImportRule(){
        return Array (
            '学生姓名' => 'student_name',
            '考试号码' => 'exam_code',
            '城市代码' => 'city_code',
            '城市' => 'city_name',
            '学校代码' => 'school_code',
            '学校名称' => 'school_name',
            '班级' => 'class_name',
            '总分' => 'socre',
            '科别代码' => 'disciplin_code',
            '科别' => 'disciplin_name',
            '是否统计' => 'statis',
            '学校性质' => 'nature',
            '星级' => 'interstellar',
            '语文' => 'ywf',
            '数学' => 'sxf',
            '英语' => 'yyf',
            '选修课1' => 'xk1f',
            '选修课2' => 'xk2f',
            '物理' => 'wlf',
            '化学' => 'hxf',
            '生物' => 'swf',
            '政治' => 'zzf',
            '历史' => 'lsf',
            '地理' => 'dlf',
            '语文1' => 'yw1f',
            '语文2' => 'yw2f',
            '语文3' => 'yw3f',
            '语文附加' => 'ywfjf',
            '数学1' => 'sx1f',
            '数学2' => 'sx2f',
            '数学附加' => 'sxfjf',
            '英语1' => 'yy1f',
            '英语2' => 'yy2f',
            '英语3' => 'yy3f',
            '物理1' => 'wl1f',
            '物理2' => 'wl2f',
            '化学1' => 'hx1f',
            '化学2' => 'hx2f',
            '生物1' => 'sw1f',
            '生物2' => 'sw2f',
            '政治1' => 'zz1f',
            '政治2' => 'zz2f',
            '历史1' => 'ls1f',
            '历史2' => 'ls2f',
            '地理1' => 'dl1f',
            '地理2' => 'dl2f'
        );
    }
    /**
     * 数组trim
     * @param type $arr
     * @return type 
     */
    public static function deepTrim($arr){
        if(is_array($arr)){
            foreach ($arr as $key=>$value){
                $arr[$key] = self::deepTrim($value);
            }
            return $arr;
        }else{
            return trim($arr);
        }
    }
    /**
     * 创建文件夹
     * @param type $dir
     * @param type $mod
     * @return type 
     */
    public static function  createDirs($dir, $mod=0777){ 
       return is_dir($dir) || (self::createDirs(dirname($dir),$mod) && mkdir($dir, 0777)); 
    }
    public static function getFileExtName($fileName){
        $extend = pathinfo($fileName);
        return strtolower($extend["extension"]);
    }
    public  static function isExcelFile($fileName){
        $extend = self::getFileExtName($fileName);
        if ($extend == 'xlsx') {
            $type = 'Excel2007';
        }elseif ($extend=='xls') {
            $type = 'Excel5';
        }else {
            $type = false;
        }
        return $type;
    }
    
    
    
    
    
    /**
     * 固定字段
     * @param type $schoolType
     * @param type $excelTH
     * @return array|boolean 
     */
    public static function getFixedCol($schoolType){
        $scoreFixedCols = array(1=>array(
                                    "exam_code" => "考生号",
                                    "student_name" => "姓名",
                                    "school_name" => "学校"),
                                2=>array(
                                    "exam_code" => "考号",
                                    "student_name" => "姓名",
                                    "school_name" => "学校")
                                );
        if(array_key_exists($schoolType, $scoreFixedCols))
                return $scoreFixedCols[$schoolType];
        return false;
    }
    private  function  ppython(){
        //参数数量
        $args_len = func_num_args();
        //参数数组
        $arg_array = func_get_args();

        //参数数量不能小于1
        if ($args_len < 1)
        {
            throw new Exception("[PPython Error] lapp_call function's arguments length < 1", PARAM_TYPE_ERROR);
        }
        //第一个参数是Python模块函数名称，必须是string类型
        if (!is_string($arg_array[0]))
        {
            throw new Exception("[PPython Error] lapp_call function's first argument must be string \"module_name::function_name\".", PARAM_TYPE_ERROR);
        }


        if (($socket = socket_create(AF_INET, SOCK_STREAM, 0)) === false)
        {
            throw new Exception("[PPython Error] socket create error.", SOCKET_ERROR);
        }

        if (socket_connect($socket, LAJP_IP, LAJP_PORT) === false)
        {
            throw new Exception("[PPython Error] socket connect error.", SOCKET_ERROR);
        }

        //消息体序列化
        $request = serialize($arg_array);
        $req_len = strlen($request);

        $request = $req_len.",".$request;

        //echo "{$request}<br>";

        $send_len = 0;
        do
        {
            //发送
            if (($sends = socket_write($socket, $request, strlen($request))) === false)
            {
                throw new Exception("[PPython Error] socket write error.", SOCKET_ERROR);
            }

            $send_len += $sends;
            $request = substr($request, $sends);

        }while ($send_len < $req_len);

        //接收
        $response = "";
        while(true)
        {
            $recv = "";
            if (($recv = socket_read($socket, 1400)) === false)
            {
                throw new Exception("[PPython Error] socket read error.", SOCKET_ERROR);
            }
            if ($recv == "")
            {
                break;
            }

            $response .= $recv;

            //echo "{$response}<br>";

        }

        //关闭
        socket_close($socket);

        $rsp_stat = substr($response, 0, 1);    //返回类型 "S":成功 "F":异常
        $rsp_msg = substr($response, 1);        //返回信息

        //echo "返回类型:{$rsp_stat},返回信息:{$rsp_msg}<br>";

        if ($rsp_stat == "F")
        {
            //异常信息不用反序列化
            throw new Exception("[PPython Error] Receive Python exception: ".$rsp_msg, LAJP_EXCEPTION);
        }
        else
        {
            if ($rsp_msg != "N") //返回非void
            {
                //反序列化
                return unserialize($rsp_msg);
            }
        }
    }
}
?>
